package owl2vowl.parser.vowl;

import owl2vowl.constants.VowlAttribute;
import owl2vowl.model.annotation.Annotation;
import owl2vowl.model.data.VowlData;
import owl2vowl.model.entities.AbstractEntity;
import owl2vowl.model.entities.nodes.classes.VowlClass;
import owl2vowl.model.entities.nodes.classes.VowlThing;
import owl2vowl.model.entities.nodes.datatypes.VowlDatatype;
import owl2vowl.model.entities.nodes.datatypes.VowlLiteral;
import owl2vowl.model.entities.properties.TypeOfProperty;
import owl2vowl.model.entities.properties.VowlDatatypeProperty;
import owl2vowl.model.entities.properties.VowlObjectProperty;
import owl2vowl.model.individuals.VowlIndividual;
import owl2vowl.model.visitor.VowlElementVisitor;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.search.EntitySearcher;

public class AnnotationVisitor implements VowlElementVisitor {
	private final VowlData vowlData;
	private final OWLOntologyManager manager;

	public AnnotationVisitor(VowlData vowlData, OWLOntologyManager manager) {
		this.vowlData = vowlData;
		this.manager = manager;
	}

	public Set<Annotation> getOntologyAnnotations(OWLOntology ontology) {
		return (Set) ontology.annotations().map(this::getVowlAnnotation).collect(Collectors.toSet());
	}

	protected Set<Annotation> getAnnotations(OWLEntity entity) {
		HashSet allAnnotations = new HashSet();
		Iterator arg2 = this.manager.getOntologies().iterator();

		while (arg2.hasNext()) {
			OWLOntology ontology = (OWLOntology) arg2.next();
			Set currentAnnotations = this
					.mapOwlAnnotationsToVowlAnnotations(EntitySearcher.getAnnotations(entity, ontology));
			allAnnotations.addAll(currentAnnotations);
		}

		return allAnnotations;
	}

	protected Set<Annotation> mapOwlAnnotationsToVowlAnnotations(Stream<OWLAnnotation> annotations) {
		return (Set) annotations.map(this::getVowlAnnotation).collect(Collectors.toSet());
	}

	protected Annotation getVowlAnnotation(OWLAnnotation annotation) {
		Annotation anno;
		if (annotation.getValue() instanceof OWLLiteral) {
			OWLLiteral val = (OWLLiteral) annotation.getValue();
			String language;
			if (val.hasLang()) {
				language = val.getLang();
				this.vowlData.addLanguage(val.getLang());
			} else {
				language = "undefined";
				this.vowlData.addLanguage("undefined");
			}

			anno = new Annotation(annotation.getProperty().toString(), val.getLiteral());
			anno.setType("label");
			anno.setLanguage(language);
		} else if (annotation.getValue() instanceof IRI) {
			anno = new Annotation(annotation.getProperty().toString(), annotation.getValue().toString());
			anno.setType("iri");
		} else {
			anno = new Annotation(annotation.getProperty().toString(), annotation.getValue().toString());
			anno.setType("label");
		}

		return anno;
	}

	protected void checkDeprecation(AbstractEntity vowlEntity) {
		if (vowlEntity.getAnnotations().isDeprecated()) {
			vowlEntity.addAttribute(VowlAttribute.DEPRECATED);
		}

	}

	public void visit(VowlThing vowlThing) {
	}

	public void visit(VowlClass vowlClass) {
		OWLClass owlClass = this.manager.getOWLDataFactory().getOWLClass(vowlClass.getIri());
		vowlClass.getAnnotations().fillAnnotations(this.getAnnotations(owlClass));
		this.checkDeprecation(vowlClass);
	}

	public void visit(VowlLiteral vowlLiteral) {
	}

	public void visit(VowlDatatype vowlDatatype) {
		OWLDatatype owlDatatype = this.manager.getOWLDataFactory().getOWLDatatype(vowlDatatype.getIri());
		vowlDatatype.getAnnotations().fillAnnotations(this.getAnnotations(owlDatatype));
		this.checkDeprecation(vowlDatatype);
	}

	public void visit(VowlObjectProperty vowlObjectProperty) {
		OWLObjectProperty owlCowlObjectPropertyass = this.manager.getOWLDataFactory()
				.getOWLObjectProperty(vowlObjectProperty.getIri());
		vowlObjectProperty.getAnnotations().fillAnnotations(this.getAnnotations(owlCowlObjectPropertyass));
		this.checkDeprecation(vowlObjectProperty);
	}

	public void visit(VowlDatatypeProperty vowlDatatypeProperty) {
		OWLDataProperty owlDataProperty = this.manager.getOWLDataFactory()
				.getOWLDataProperty(vowlDatatypeProperty.getIri());
		vowlDatatypeProperty.getAnnotations().fillAnnotations(this.getAnnotations(owlDataProperty));
		this.checkDeprecation(vowlDatatypeProperty);
	}

	public void visit(VowlIndividual vowlIndividual) {
		OWLNamedIndividual owlNamedIndividual = this.manager.getOWLDataFactory()
				.getOWLNamedIndividual(vowlIndividual.getIri());
		vowlIndividual.getAnnotations().fillAnnotations(this.getAnnotations(owlNamedIndividual));
	}

	public void visit(TypeOfProperty typeOfProperty) {
	}
}